package com.zxy.ziems.server.device.service.impl;

import cn.hutool.core.util.StrUtil;
import com.zxy.btp.common.response.PageResult;
import com.zxy.btp.common.util.JsonUtils;
import com.zxy.ziems.server.collection.pojo.entity.CollectionDevicePropertyParam;
import com.zxy.ziems.server.device.convertor.DeviceConvertor;
import com.zxy.ziems.server.device.mapper.DevicePropertyMapper;
import com.zxy.ziems.server.device.modules.impl.DevicePropertyProcessorManager;
import com.zxy.ziems.server.device.pojo.dto.DevicePropertyDTO;
import com.zxy.ziems.server.device.pojo.entity.*;
import com.zxy.ziems.server.device.pojo.vo.DevicePropertyVO;
import com.zxy.ziems.server.device.service.*;
import com.zxy.ziems.server.mybatis.core.pojo.PageParam;
import com.zxy.ziems.server.mybatis.core.query.LambdaQueryWrapperX;
import com.zxy.ziems.server.mybatis.core.query.WrapperX;
import com.zxy.ziems.server.mybatis.core.service.ServiceImplX;
import com.zxy.ziems.server.utils.AssertUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备关联属性
 *
 * @author 10348359
 * @create 2024-03-20 22:43
 */
@Service
@Slf4j
public class DevicePropertyServiceImpl extends ServiceImplX<DevicePropertyMapper, DevicePropertyEntity>
        implements DevicePropertyService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(DevicePropertyDTO dto) {

        DeviceEntity deviceEntity = deviceService.getById(dto.getDeviceId());
        AssertUtil.nonNull(deviceEntity, "设备不存在");
        ChannelDeviceEntity channelDeviceEntity = channelDeviceService.getByDeviceId(deviceEntity.getId());
        AssertUtil.nonNull(channelDeviceEntity, "设备没有被添加通道中，请先添加");

        ChannelEntity channelEntity = channelService.getById(channelDeviceEntity.getChannelId());
        AssertUtil.nonNull(channelEntity, "通讯通道不存在");
        AssertUtil.isTrue(Objects.equals(channelEntity.getDeviceTypeCode(), deviceEntity.getTypeCode()), "通讯通道与设备了下不匹配");
        ProtocolEntity protocolEntity = protocolService.getById(channelEntity.getProtocolId());
        AssertUtil.nonNull(protocolEntity, "协议不存在");
        AssertUtil.isNull(getByData(dto.getDataTypeId(), dto.getDeviceId()), "设备属性名称重复");
        AssertUtil.nonNull(dataTypeService.getById(dto.getDataTypeId()), "设备属性不存在");
        AssertUtil.nonNull(dataUnitService.getById(dto.getUnitId()), "设备的数据单位不存在");

        DevicePropertyEntity entity = DeviceConvertor.INSTANCE.devicePropertyDTOConvert2DO(dto);
        String protocol = protocolEntity.getCode();
        String deviceId = dto.getDeviceId();
        String dataTypeId = entity.getDataTypeId();
        processorManager.doProcessAdvancedConfigIfPresentBy(
                protocol,
                dto.getAdvanced(),
                (processor, o) -> {
                    processor.doBeforeEncodeAdvancedConfigActionTrigger(o, protocol, deviceId, dataTypeId);
                    if (Objects.nonNull(o)) {
                        entity.setAdvanced(JsonUtils.toJSONString(o));
                    }
                });
        save(entity);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bind(DevicePropertyDTO dto) {

        DeviceEntity deviceEntity = deviceService.getById(dto.getDeviceId());
        AssertUtil.nonNull(deviceEntity, "设备不存在");

        AssertUtil.isNull(getByData(dto.getDataTypeId(), dto.getDeviceId()), "设备属性名称重复");
        AssertUtil.nonNull(dataTypeService.getById(dto.getDataTypeId()), "设备属性不存在");
        AssertUtil.nonNull(typePropertyService.getByDevice(deviceEntity.getTypeCode(), dto.getDataTypeId()), "设备类别未关联该属性");
        AssertUtil.nonNull(dataUnitService.getById(dto.getUnitId()), "设备的数据单位不存在");
        AssertUtil.nonNull(dataUnitService.getById(dto.getDataUnitId()), "设备的数据单位不存在");

        DevicePropertyEntity entity = DeviceConvertor.INSTANCE.devicePropertyDTOConvert2DO(dto);
        save(entity);

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(DevicePropertyDTO dto) {

        DeviceEntity deviceEntity = deviceService.getById(dto.getDeviceId());
        AssertUtil.nonNull(deviceEntity, "设备不存在");
        ChannelDeviceEntity channelDeviceEntity = channelDeviceService.getByDeviceId(deviceEntity.getId());
        AssertUtil.nonNull(channelDeviceEntity, "设备没有被添加通道中，请先添加");
        ChannelEntity channelEntity = channelService.getById(channelDeviceEntity.getChannelId());
        AssertUtil.nonNull(channelEntity, "通讯通道不存在");
        AssertUtil.isTrue(Objects.equals(channelEntity.getDeviceTypeCode(), deviceEntity.getTypeCode()), "通讯通道与设备了下不匹配");
        ProtocolEntity protocolEntity = protocolService.getById(channelEntity.getProtocolId());
        AssertUtil.nonNull(protocolEntity, "协议不存在");

        AssertUtil.nonNull(getById(dto.getId()), "设备属性不存在");
        DevicePropertyEntity old = getByData(dto.getDataTypeId(), dto.getDeviceId());
        AssertUtil.isFalse(Objects.isNull(old) || !old.getId().equals(dto.getId()), "设备属性重复");
        AssertUtil.nonNull(dataTypeService.getById(dto.getDataTypeId()), "设备属性不存在");
        AssertUtil.nonNull(dataUnitService.getById(dto.getUnitId()), "设备的数据单位不存在");

        DevicePropertyEntity entity = DeviceConvertor.INSTANCE.devicePropertyDTOConvert2DO(dto);
        String protocol = protocolEntity.getCode();
        String deviceId = dto.getDeviceId();
        String dataTypeId = entity.getDataTypeId();
        processorManager.doProcessAdvancedConfigIfPresentBy(
                protocol,
                dto.getAdvanced(),
                (processor, o) -> {
                    processor.doBeforeEncodeAdvancedConfigActionTrigger(o, protocol, deviceId, dataTypeId);
                    if (Objects.nonNull(o)) {
                        entity.setAdvanced(JsonUtils.toJSONString(o));
                    }
                });
        updateById(entity);
    }

    @Override
    public boolean deleteCheckById(String id) {
        if (StrUtil.isBlank(id)) {
            return false;
        }

        DevicePropertyEntity entity = getById(id);
        if (!entity.getCollectInterval().equals("1000")) {
            return false;
        }
        if (StringUtils.isNotBlank(entity.getAdvanced())) {
            return false;
        }


        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(String id) {
        if (StrUtil.isBlank(id)) {
            return;
        }
        DevicePropertyEntity entity = getById(id);
        AssertUtil.nonNull(entity, "属性不存在");

        removeById(id);
    }

    @Override
    public DevicePropertyEntity getBy(String deviceId, String dataTypeId) {
        if (StrUtil.isBlank(deviceId) || StrUtil.isBlank(dataTypeId)) {
            return null;
        }

        return getOne(WrapperX.<DevicePropertyEntity>lambdaQuery()
                .eq(DevicePropertyEntity::getDeviceId, deviceId)
                .eq(DevicePropertyEntity::getDataTypeId, dataTypeId));
    }

    @Override
    public List<DevicePropertyEntity> listByDeviceIds(Collection<? extends Serializable> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return new ArrayList<>();
        }
        return list(DevicePropertyEntity::getDeviceId, ids);
    }

    @Override
    public List<DevicePropertyEntity> listByDeviceId(String deviceId) {
        DeviceEntity deviceEntity = deviceService.getById(deviceId);
        AssertUtil.nonNull(deviceEntity, "设备不存在");
        LambdaQueryWrapperX<DevicePropertyEntity> wrapperX = new LambdaQueryWrapperX<>();
        wrapperX.eq(DevicePropertyEntity::getDeviceId, deviceId);
        return baseMapper.selectList(wrapperX);
    }

    @Override
    public List<DevicePropertyVO> viewListByDeviceId(String deviceId) {
        DeviceEntity deviceEntity = deviceService.getById(deviceId);
        AssertUtil.nonNull(deviceEntity, "设备不存在");

        List<DevicePropertyEntity> list = baseMapper.selectListBy(deviceId, deviceEntity.getTypeCode());
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>(0);
        }
        Set<String> propertyIdSet = new HashSet<String>();
        Set<String> unitIdSet = new HashSet<>();
        list.forEach((entity) -> {
            if (Objects.nonNull(entity.getDataTypeId())) {
                propertyIdSet.add(entity.getDataTypeId());
            }
            if (Objects.nonNull(entity.getUnitId())) {
                unitIdSet.add(entity.getUnitId());
            }
            if (Objects.nonNull(entity.getDataUnitId())) {
                unitIdSet.add(entity.getDataUnitId());
            }
        });

        List<DataUnitEntity> unitList = dataUnitService.listByIdList(unitIdSet);
        List<DataTypeEntity> dataTypeEntityList = dataTypeService.listByIdList(propertyIdSet);
        Map<String, DataUnitEntity> unitMap = unitList.stream().collect(Collectors.toMap(DataUnitEntity::getId, (a) -> a));
        Map<String, DataTypeEntity> dataTypeEntityMap = dataTypeEntityList.stream().collect(Collectors.toMap(DataTypeEntity::getId, (a) -> a));
        List<DeviceTypePropertyEntity> typePropertyList = typePropertyService.listByDeviceType(deviceEntity.getTypeCode());
        Set<String> typePropertyIdSet = typePropertyList.stream().map(DeviceTypePropertyEntity::getDataTypeId).collect(Collectors.toSet());

        ProtocolEntity protocolEntity = protocolService.getByChannelId(deviceEntity.getChannelId());

        DeviceConvertor instance = DeviceConvertor.INSTANCE;
        List<DevicePropertyVO> result = list.stream()
                .map((entity) -> {
                    DevicePropertyVO vo = instance.devicePropertyDOConvert2VO(
                            entity,
                            dataTypeEntityMap.get(entity.getDataTypeId()),
                            unitMap.get(entity.getUnitId()),
                            Objects.nonNull(entity.getDataUnitId()) ? unitMap.get(entity.getDataUnitId()) : null,
                            typePropertyIdSet.contains(entity.getDataTypeId()) ? DevicePropertyVO.META_STATUS : DevicePropertyVO.CUSTOM_STATUS
                    );
                    String protocol = Objects.nonNull(protocolEntity) ? protocolEntity.getCode() : null;
                    String dataTypeId = entity.getDataTypeId();
                    processorManager.doProcessDecodeAdvancedConfigIfPresentBy(
                            protocol,
                            entity.getAdvanced(),
                            (p, config) -> {
                                Object o = p.doDecodeAdvancedConfig(config, protocol, deviceId, dataTypeId);
                                vo.setAdvanced(o);
                            }
                    );
                    return vo;
                })
                .toList();
        return result;
    }

    @Override
    public void addDataTypeAndUnit(DevicePropertyDTO<Object> dto) {
        DeviceEntity deviceEntity = deviceService.getById(dto.getDeviceId());
        AssertUtil.nonNull(deviceEntity, "设备不存在");

        AssertUtil.isNull(getByData(dto.getDataTypeId(), dto.getDeviceId()), "设备属性名称重复");

        final DataTypeEntity dataTypeEntity = dataTypeService.getById(dto.getDataTypeId());
        AssertUtil.nonNull(dataTypeEntity, "设备属性不存在");
        if (StringUtils.isBlank(dto.getName())) {
            dto.setName(dataTypeEntity.getName());
        }
        AssertUtil.nonNull(typePropertyService.getByDevice(deviceEntity.getTypeCode(), dto.getDataTypeId()), "设备类别未关联该属性");
        AssertUtil.nonNull(dataUnitService.getById(dto.getUnitId()), "设备的数据单位不存在");

        DevicePropertyEntity entity = DeviceConvertor.INSTANCE.devicePropertyDTOConvert2DO(dto);
        save(entity);
    }

    @Override
    public void updateDataTypeAndUnit(DevicePropertyDTO<Object> dto) {
        DeviceEntity deviceEntity = deviceService.getById(dto.getDeviceId());
        AssertUtil.nonNull(deviceEntity, "设备不存在");

        AssertUtil.nonNull(getById(dto.getId()), "设备属性不存在");
        DevicePropertyEntity old = getByData(dto.getDataTypeId(), dto.getDeviceId());
        AssertUtil.isFalse(Objects.isNull(old) || !old.getId().equals(dto.getId()), "设备属性重复");
        AssertUtil.nonNull(dataTypeService.getById(dto.getDataTypeId()), "设备属性不存在");
        AssertUtil.nonNull(dataUnitService.getById(dto.getUnitId()), "设备的数据单位不存在");

        DevicePropertyEntity entity = DeviceConvertor.INSTANCE.devicePropertyDTOConvert2DO(dto);
        saveOrUpdate(entity);
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectDeviceProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectDeviceProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectDlDeviceProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectDlDeviceProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectDeviceFmcsRealProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectDeviceFmcsRealProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectFmcsDl(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectFmcsDlDeviceProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectDeviceFmcsPvProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectDeviceFmcsPvProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectDeviceFmcsProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectDeviceFmcsProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectDeviceWaterDlProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectDeviceWaterDlProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectDeviceWaterChemicalProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectDeviceWaterChemicalProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectDeviceCIMDlProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectDeviceCIMDlProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectDeviceCIMWaterProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectDeviceCIMWaterProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectDeviceCIMGasProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectDeviceCIMGasProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectManualInputNaturalGasProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectManualInputNaturalGasProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectManualInputChemicalsProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectManualInputChemicalsProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectDeviceWaterProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectDeviceWaterProperty(page, param));
    }

    @Override
    public PageResult<CollectionDevicePropertyParam> selectDeviceWaterTotalRealProperty(PageParam pageParam) {
        return customPage(pageParam, (page, param) -> baseMapper.selectDeviceWaterTotalRealProperty(page, param));
    }


    private DevicePropertyEntity getByData(String dataTypeId, String deviceId) {
        return getOne(WrapperX.<DevicePropertyEntity>lambdaQuery()
                .eq(DevicePropertyEntity::getDataTypeId, dataTypeId)
                .eq(DevicePropertyEntity::getDeviceId, deviceId)
        );
    }


    private DevicePropertyProcessorManager processorManager;

    @Autowired
    public void setProcessorManager(DevicePropertyProcessorManager devicePropertyProcessorManager) {
        this.processorManager = devicePropertyProcessorManager;
    }

    private DataTypeService dataTypeService;

    @Autowired
    public void setDataTypeService(DataTypeService dataTypeService) {
        this.dataTypeService = dataTypeService;
    }

    private DataUnitService dataUnitService;

    @Autowired
    public void setDataUnitService(DataUnitService dataUnitService) {
        this.dataUnitService = dataUnitService;
    }


    private DeviceService deviceService;

    @Autowired
    public void setDeviceService(DeviceService deviceService) {
        this.deviceService = deviceService;
    }

    private ProtocolService protocolService;

    @Autowired
    public void setProtocolService(ProtocolService protocolService) {
        this.protocolService = protocolService;
    }

    private ChannelService channelService;

    @Autowired
    public void setChannelService(ChannelService channelService) {
        this.channelService = channelService;
    }

    private DeviceTypePropertyService typePropertyService;

    @Autowired
    public void setTypePropertyService(DeviceTypePropertyService deviceTypePropertyService) {
        this.typePropertyService = deviceTypePropertyService;
    }

    private ChannelDeviceService channelDeviceService;

    @Autowired
    public void setChannelDeviceService(ChannelDeviceService channelDeviceService) {
        this.channelDeviceService = channelDeviceService;
    }
}
